#include "ota.h"
#include "ota_update.h"
#include "BussinessTerminalManage.h"
#include <pthread.h>
#include "common.h"

extern ob_context g_mqtt_ob;
extern ST_MODEL_CTL g_st_model_ctl;
static int recmdCount = 0;
static char recmdArray[50][32] = {0};
static int g_restart_flag = 0;
static int g_process_flag = 0;
//static pthread_mutex_t g_mutex;

bool JsonToStruct_DownloadOTAPack(char *pcJson, ST_IOTA_LOG *pcStatusDecs)
{
    cJSON *json = NULL;
    cJSON *param = NULL;
    json = cJSON_Parse(pcJson);
    if (json)
    {
        pcStatusDecs->iMid = strdup(cJSON_GetObjectItem(json, "mid")->valuestring);
        pcStatusDecs->deviceSn = strdup(cJSON_GetObjectItem(json, "deviceSn")->valuestring);
        pcStatusDecs->Servicename = strdup(cJSON_GetObjectItem(json, "service")->valuestring);
        pcStatusDecs->zone = strdup(cJSON_GetObjectItem(json, "zone")->valuestring);
        pcStatusDecs->node = strdup(cJSON_GetObjectItem(json, "node")->valuestring);
        pcStatusDecs->msgTime = strdup(cJSON_GetObjectItem(json, "msgTime")->valuestring);
        pcStatusDecs->deviceID = strdup(cJSON_GetObjectItem(json, "deviceSn")->valuestring);

        if (cJSON_HasObjectItem(json, "params"))
        {
            param = cJSON_GetObjectItem(json, "params");
            IOTA_OTA_PARAM *st_param = pcStatusDecs->param;
            if (cJSON_HasObjectItem(param, "fileId"))
            	st_param->fileId = strdup(cJSON_GetObjectItem(param, "fileId")->valuestring);
	    if (cJSON_HasObjectItem(param, "filename"))
            	st_param->filename = strdup(cJSON_GetObjectItem(param, "filename")->valuestring);
	    if (cJSON_HasObjectItem(param, "fileType"))
            	st_param->fileType = strdup(cJSON_GetObjectItem(param, "fileType")->valuestring);
            if (cJSON_HasObjectItem(param, "digestAlgorithm"))
            	st_param->digestAlgorithm = strdup(cJSON_GetObjectItem(param, "digestAlgorithm")->valuestring);
            if (cJSON_HasObjectItem(param, "digest"))
            	st_param->digest = strdup(cJSON_GetObjectItem(param, "digest")->valuestring);
            else
            	st_param->digest = NULL;
            if (cJSON_HasObjectItem(param, "fileLink"))
            	st_param->fileLink = strdup(cJSON_GetObjectItem(param, "fileLink")->valuestring);
            if (cJSON_HasObjectItem(param, "size"))
            	st_param->size = cJSON_GetObjectItem(param, "size")->valueint;
            if (cJSON_HasObjectItem(param, "otaType"))
            	st_param->otaType = cJSON_GetObjectItem(param, "otaType")->valueint;
            	
            if (cJSON_HasObjectItem(param, "pkgSpace"))
            	st_param->pkgSpace = cJSON_GetObjectItem(param, "pkgSpace")->valueint;
        }
        cJSON_Delete(json);
        return true;
    }
    else
    {
        return false;
    }
}

bool JsonToStruct_DownloadOTAPackUpdate(char *pcJson, ST_IOTA_LOG *pcStatusDecs)
{
    cJSON *json = NULL;
    cJSON *param = NULL;
    json = cJSON_Parse(pcJson);
    if (json)
    {
        pcStatusDecs->iMid = strdup(cJSON_GetObjectItem(json, "mid")->valuestring);
        pcStatusDecs->deviceSn = strdup(cJSON_GetObjectItem(json, "deviceSn")->valuestring);
        pcStatusDecs->Servicename = strdup(cJSON_GetObjectItem(json, "service")->valuestring);
        pcStatusDecs->zone = strdup(cJSON_GetObjectItem(json, "zone")->valuestring);
        pcStatusDecs->node = strdup(cJSON_GetObjectItem(json, "node")->valuestring);
        if (cJSON_HasObjectItem(json, "requestId") && strlen(cJSON_GetObjectItem(json, "requestId")->valuestring) > 0)
        {
            pcStatusDecs->requestID = strdup(cJSON_GetObjectItem(json, "requestId")->valuestring);
        }
        else
        {
            pcStatusDecs->requestID = strdup("com.jxtech.iot_ops - tasks");
        }
        pcStatusDecs->msgTime = strdup(cJSON_GetObjectItem(json, "msgTime")->valuestring);
        pcStatusDecs->deviceID = strdup(cJSON_GetObjectItem(json, "deviceSn")->valuestring);

        if (cJSON_HasObjectItem(json, "params"))
        {
            param = cJSON_GetObjectItem(json, "params");
            IOTA_OTA_UPDATE_PARAM *st_param = pcStatusDecs->param;
            if (cJSON_HasObjectItem(param, "patchId"))
            st_param->patchId = strdup(cJSON_GetObjectItem(param, "patchId")->valuestring);
            if (cJSON_HasObjectItem(param, "patchName"))
            	st_param->patchName = strdup(cJSON_GetObjectItem(param, "patchName")->valuestring);
            if (cJSON_HasObjectItem(param, "patchVersion"))
            	st_param->patchVersion = strdup(cJSON_GetObjectItem(param, "patchVersion")->valuestring);
            if (cJSON_HasObjectItem(param, "fileId"))
            	st_param->fileId = strdup(cJSON_GetObjectItem(param, "fileId")->valuestring);
            if (cJSON_HasObjectItem(param, "otaType"))
            	st_param->otaType = cJSON_GetObjectItem(param, "otaType")->valueint;
            if (cJSON_HasObjectItem(param, "filename"))
            	st_param->filename = strdup(cJSON_GetObjectItem(param, "filename")->valuestring);
            if (cJSON_HasObjectItem(param, "deviceType"))
            {
                st_param->deviceType = cJSON_GetObjectItem(param, "deviceType")->valueint;
            }
            else
            {
                st_param->deviceType = 0;
            }
            if (cJSON_HasObjectItem(param, "subDeviceId"))
            {
                st_param->subDeviceid = strdup(cJSON_GetObjectItem(param, "subDeviceId")->valuestring);
            }
            else
            {
                st_param->subDeviceid = NULL;
            }
        }
        cJSON_Delete(json);
        return true;
    }
    else
    {
        return false;
    }
}
static int preDiskCapacity(int packSize)
{
	char cmd[1024] = {0};
	char path[1024] = {0};
	char result[1024] = {0};
	strcpy(path,APP_FILE_PATH);
	char *p = path;
	p++;
	while(*p != '/' && *p != '\0')
	{
		p++;
	}
	*p = '\0';
	sprintf(cmd, "df | grep %s | awk \'END {printf $4}\'", path);
	
	FILE *fp = popen(cmd, "r");
        if (fp == NULL)
        {
            dzlog_info("df grep popen error");
            return -1;
        }
       
        if (fgets(result, sizeof(result), fp) <= 0)
        {
            dzlog_info("df grep error result = %s", result);
            pclose(fp);
            return -1;
        }

        pclose(fp);
	
	(result[strlen(result) - 1] == '\n') && (result[strlen(result) - 1] = '\0');
	strcat(result,"0");
	strcat(result,"0");
	strcat(result,"0");
	char result1[1024] = {0};
	sprintf(result1,"%d",packSize);
	if(strlen(result) > strlen(result1))
	{
		return 0;
	}
	else if(strlen(result) < strlen(result1) || strcmp(result,result1) < 0)
	{
		dzlog_info("df grep error result = %s ,packSize = %d", result,packSize);
		return -1;
	}
	return 0;
}

/// @brief 下载升级包
/// @param arg
/// @return
int ota_download_file(char *arg)
{
    // 下载文件
    ProgressInfo info1;
    memcpy(&info1,arg,sizeof(ProgressInfo));
    ProgressInfo *info = &info1;
    int *ret = malloc(sizeof(int));
    char full_filename[200] = {0};
    strcpy(full_filename, info->filename);

    *ret = file_download(full_filename, info);
    info->ret = *ret;
    pthread_exit((void *)ret);
}
/// @brief 下载升级线程
/// @param pcJson
/// @return
int ota_download_pthread(char *pcJson)
{
    dzlog_info("ota download start");
    ST_IOTA_LOG log;
    IOTA_OTA_PARAM param;
    param.pkgSpace = 0;
    param.size = 0;
    log.param = &param;
    JsonToStruct_DownloadOTAPack(pcJson, &log);
    char *psJson;
    char uid[80] = {0};
    GF_GetGUID(uid);
    ST_IOTA_LOG_RES log_res;
    log_res.body = "";
    log_res.deviceID = log.deviceID;
    log_res.deviceSn = log.deviceSn;
    log_res.iMid = uid;
    log_res.node = log.node;
    log_res.requestID = NULL;
    log_res.replyId = log.iMid;
    log_res.zone = log.zone;
    bool isError = false;

    // 开始下载
    log_res.code = 100;
    dzlog_info("Start download:%s", param.filename);
    StructToJson_LogUploadRes(&psJson, &log_res, true);
    int ret = IOTA_SendMqtt("/v1/devices/ota/response", psJson, strlen(psJson));
    free_s(psJson);

    ProgressInfo info;
    strcpy(info.fileid, param.fileId);
    strcpy(info.md5, param.digest);
    info.filesize = param.size;
    // 1 下载 2 上传
    info.action = 1;
    info.ret = 0;
    info.Progress = 0;
    info.Bytes = 0;
    info.stop = 0;
    ////////////////////////////////////////check

    if(g_process_flag)
    {
    	isError = true;
        log_res.code = 559;
        dzlog_info("error: g_process_flag:%d",g_process_flag);
        goto Uerror;
    }
    g_process_flag = 1; 
    
     if (param.size <= 0)
    {
        isError = true;
        log_res.code = 400;
        dzlog_info("error:param.size:%d", param.size);
        goto Uerror;
    }
    
    dzlog_info("param.otaType:%d", param.otaType);
    if (param.otaType != 11 && param.otaType != 12)
    {
        isError = true;
        log_res.code = 404;
        goto Uerror;
    }
    if(!strstr(param.filename,"tar.gz") && param.otaType != 2)
    {
    	isError = true;
        log_res.code = 506;
        goto Uerror;
    }
    
    
    ////////////////////////////////////////check
    // 下载文件
    int ret0 = checkAndCreateDirectory(APP_FILE_PATH);
    if (ret0 == 0)
    {
        log_res.code = 500;
        isError = true;
        dzlog_error("create directory error");
        goto Uerror;
    }
    char file_full[4096] = {0};
    dzlog_info("ota download start 33");
    char file_dir_cmd[1024] = {0};
    /// test
    // strcpy(param.fileId,"1871393959723077632");
    ///
    sprintf(file_dir_cmd, "mkdir %s/%s", APP_FILE_PATH, param.fileId);
    system(file_dir_cmd);
    sprintf(file_full, "%s/%s/%s", APP_FILE_PATH, param.fileId, param.filename);
    dzlog_info("The file [%s]", file_full);
    strcpy(info.filename, file_full);

    struct stat st = {0};

    bool needtodownload = false;
    int progress = 0;
    // 分线程
    pthread_t thread;
    if (stat(file_full, &st) == -1)
    {
        dzlog_info("not found The file [%s]", file_full);
        needtodownload = true;
        // 创建线程
        pthread_create(&thread, NULL, ota_download_file, &info);
    }
    else
    {
        dzlog_info("The file already exists locally.[%s]", file_full);
        // 校验sha256
        if (strcmp(param.digestAlgorithm, "md5") == 0)
        {
            unsigned char hash_md5[MD5_DIGEST_LENGTH * 2 + 1];
            calculate_md5(file_full, hash_md5);
            if (strcmp(hash_md5, param.digest) != 0)
            {
                needtodownload = true;
            }
            else
            {
                progress = 100;
            }
        }
        else if (strcmp(param.digestAlgorithm, "sha256") == 0)
        {
            unsigned char hash_sha256[SHA256_DIGEST_LENGTH * 2 + 1];
            calculate_file_sha256(file_full, hash_sha256);
            if (strcmp(hash_sha256, param.digest) != 0)
            {
                needtodownload = true;
            }
            else
            {
                progress = 100;
            }
        }
        else
        {
            needtodownload = true;
        }
        /// test
        // needtodownload = false;
        // progress = 100;
        ///
        if (needtodownload)
        {
            dzlog_info("The file already exists locally, but the verification is incorrect.[%s]", file_full);
            // 创建线程
            pthread_create(&thread, NULL, ota_download_file, &info);
        }
        else
        {
            info.Progress = 100;
            progress = 100;
        }
    }

    // 读取进度
    int retry = 0;

    //int *iRet = NULL;

    off_t cur_size = 0;
    int flag = 0;
    while (cur_size < param.size && needtodownload)
    {
        sleep(5);
        struct stat file_inf = {0};

        stat(file_full, &file_inf);

        if (cur_size == file_inf.st_size)
        {
            retry++;
            if (retry > 60)
            {
                flag = 1;
                break;
            }

            // 如果大小不变，即进度不变，则不再重复上报进度
            continue;
        }
        cur_size = file_inf.st_size;
        dzlog_info("file_full[%s], size = %ld", file_full, file_inf.st_size);
        progress = 100 * cur_size / param.size;
        dzlog_debug("ota_download progress = %d", progress);
        memset(uid, 0, 64);
        GF_GetGUID(uid);
        log_res.iMid = uid;
        send_progress(115, progress, &log_res);
    }

    dzlog_info("ota_download 11");
    /*
if (needtodownload)
{
// 等待线程结束
pthread_join(thread, (void**)&iRet);
}
else
{
int ii = 0;
iRet = (int*)malloc(sizeof(int));
*iRet = &ii;
}


if (*iRet == -1)
{
dzlog_error("下载出错：无法连接到或登录到文件服务器");
isError = true;
log_res.code = 520;
goto Uerror;
}
else if (*iRet == -2)
{
dzlog_error("下载出错：文件服务器无法查询到该文件");
isError = true;
log_res.code = 521;

goto Uerror;
}
else if (*iRet == -3)
{
dzlog_error("下载出错：文件下载超时或出错");
isError = true;
log_res.code = 522;
goto Uerror;
}
else*/
    if (progress == 100) ///*test*/ && needtodownload/*test*/)
    {
        // 校验sha256
        if (strcmp(param.digestAlgorithm, "md5") == 0)
        {
            unsigned char hash_md5[MD5_DIGEST_LENGTH * 2 + 1];
            calculate_md5(file_full, hash_md5);
            if (strcmp(hash_md5, param.digest) != 0)
            {
                log_res.code = 420;
                isError = true;
                dzlog_error("Verification error:%s", hash_md5);
                goto Uerror;
            }
        }
        else if (strcmp(param.digestAlgorithm, "sha256") == 0)
        {
            unsigned char hash_sha256[SHA256_DIGEST_LENGTH * 2 + 1];
            calculate_file_sha256(file_full, hash_sha256);
            if (strcmp(hash_sha256, param.digest) != 0)
            {
                log_res.code = 420;
                isError = true;
                dzlog_error("Verification error:%s", hash_sha256);
                goto Uerror;
            }
        }
        else
        {
            log_res.code = 500;
            isError = true;
            dzlog_error("can not support hash %s", param.digestAlgorithm);
            goto Uerror;
        }
    }

    // 下载校验完成
    // if (info.downloadProgress == 100)

    if (progress == 100)
    {
        GF_GetGUID(uid);
        log_res.code = 200;
        log_res.body = "download ok";
        dzlog_info("1 finish download:%s", param.filename);
        StructToJson_LogUploadRes(&psJson, &log_res, true);
        ret = IOTA_SendMqtt("/v1/devices/ota/response", psJson, strlen(psJson));
        dzlog_info("2 finish download:[%s]", psJson);
    }
    else
    {
        log_res.code = 557;
        isError = true;
        dzlog_error("not finish download:%s ,progress = %d", param.filename, progress);
    }

Uerror:
    if (isError)
    {
        GF_GetGUID(uid);
        log_res.iMid = uid;
        StructToJson_LogUploadRes(&psJson, &log_res, true);
        IOTA_SendMqtt("/v1/devices/ota/response", psJson, strlen(psJson));
        g_process_flag = 0;
    }
/*    if(needtodownload)
    {
    	
    	pthread_join(thread,NULL);
    		
    }*/
Ufree:
            /*
    if (log_res.code != 421 || log_res.code != 423)
    {
        memset(info.fileid, 0, sizeof(info.fileid));
        memset(info.filename, 0, sizeof(info.filename));
        memset(info.md5, 0, sizeof(info.md5));
    }*/
    free_s(log.iMid);
    free_s(log.deviceSn);
    free_s(log.deviceID);
    free_s(log.msgTime);
    free_s(log.node);
    free_s(log.Servicename);
    free_s(log.zone);
    free_s(param.digest);
    free_s(param.digestAlgorithm);
    free_s(param.fileId);
    free_s(param.fileLink);
    free_s(param.filename);
    free_s(param.fileType);
    free_s(psJson);
    free_s(pcJson);

    //free_s(iRet);
    return 0;
}

int ota_download(char *pcJson)
{ // 分线程
    pthread_t thread;
    pthread_attr_t attr;
    char *psJson = strdup(pcJson);
    // 初始化线程属性
    pthread_attr_init(&attr);

    // 将线程设置为分离状态
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

    // 创建线程
    pthread_create(&thread, &attr, ota_download_pthread, psJson);
    // 销毁线程属性对象
    pthread_attr_destroy(&attr);
    return 0;
}

int putJsonToOtaFile(char *pcJson)
{
    dzlog_info("pcjson = %s", pcJson);

    FILE *json = NULL;
    json = fopen("./otaEagleEyeSMG.json", "wb+");
    if (json == NULL)
    {
        dzlog_error("can not create file");
        return -1;
    }

    fputs(pcJson, json);
    fclose(json);
    dzlog_info("putJsonToOtaFile finish!!!");
    return 0;
}
static int putJsonTonvr_firmwareFile(char *pcJson)
{
    dzlog_info("pcjson = %s", pcJson);

    FILE *json = NULL;
    json = fopen("./nvr_firmware.json", "wb+");
    if (json == NULL)
    {
        dzlog_error("can not create file nvr_firmware.json");
        return -1;
    }

    fputs(pcJson, json);
    fclose(json);
    /*
    FILE *fp1 = popen("devinfo -a | grep \"firmware version:\" > nvr_firmware.ini", "r");
    if (json == NULL)
    {
        dzlog_error("can not create file nvr_firmware.ini");
        return -1;
    }
    pclose(fp1);
    dzlog_info("putJsonTonvr_firmwareFile finish!!!");*/
    return 0;
}
static int putJsonTonvr_algorithmFile(char *pcJson)
{
    dzlog_info("pcjson = %s", pcJson);

    FILE *json = NULL;
    json = fopen("./nvr_algorithm.json", "wb+");
    if (json == NULL)
    {
        dzlog_error("can not create file nvr_algorithm.json");
        return -1;
    }

    fputs(pcJson, json);
    fclose(json);
    /*
    FILE *fp1 = popen("devinfo -a | grep \"firmware version:\" > nvr_firmware.ini", "r");
    if (json == NULL)
    {
        dzlog_error("can not create file nvr_firmware.ini");
        return -1;
    }
    pclose(fp1);
    dzlog_info("putJsonTonvr_firmwareFile finish!!!");*/
    return 0;
}
/// @brief 程序安装
/// @param pcJson
/// @return
int ota_install_pthread(char *pcJson)
{
    /// test
    // while(1);
    ///
    ST_IOTA_LOG log;
    IOTA_OTA_UPDATE_PARAM param;
    log.param = &param;
    JsonToStruct_DownloadOTAPackUpdate(pcJson, &log);

    char *psJson = NULL;
    char uid[80] = {0};
    GF_GetGUID(uid);
    ST_IOTA_LOG_RES log_res;
    log_res.body = "";
    log_res.deviceID = log.deviceID;
    log_res.deviceSn = log.deviceSn;
    log_res.iMid = uid;
    log_res.node = log.node;
    log_res.replyId = log.iMid;
    log_res.zone = log.zone;
    log_res.requestID = log.requestID;
    log_res.deviceType = param.deviceType;
    log_res.subDeviceId = "";

    bool isError = false;

    // 开始升级
    log_res.code = 100;
    log_res.body = "update";
    dzlog_info("Start update:%s %s", param.patchName, param.patchVersion);
    StructToJson_LogUploadRes(&psJson, &log_res, true);
    IOTA_SendMqtt("/v1/devices/ota/response", psJson, strlen(psJson));
    free_s(psJson);

    int ret = 0;
    // 校验设备

    if (param.otaType == 2 && param.deviceType == 0)
    {
        if ((ret = update_check(param)) == 1)
        {
            // 校验成功
            GF_GetGUID(uid);
            log_res.code = 101;
            log_res.body = "check success";
            dzlog_info("check success:%s", param.patchName);
            StructToJson_LogUploadRes(&psJson, &log_res, true);
            IOTA_SendMqtt("/v1/devices/ota/response", psJson, strlen(psJson));
            free_s(psJson);
        }
        else
        {
            // 校验失败
            GF_GetGUID(uid);
            log_res.code = ret;
            log_res.body = "check success";
            dzlog_info("check success:%s", param.patchName);
            StructToJson_LogUploadRes(&psJson, &log_res, true);
            IOTA_SendMqtt("/v1/devices/ota/response", psJson, strlen(psJson));
            free_s(psJson);
        }
    }

    dzlog_debug("deviceType = %d,otaType = %d", param.deviceType, param.otaType);

    ////////////////////////appm single way
    //pthread_mutex_lock(&g_mutex);

    // 网关nvr
    if (param.deviceType == 0)
    {
        // 固件升级
        if (param.otaType == 1)
        {

            if (putJsonTonvr_firmwareFile(pcJson) == 0)
                ret = nvr_firmware_update(param, param.filename, &log_res);
            else
                ret = 505;
        }
        // 应用升级
        else if (param.otaType == 2)
        {
            ret = nvr_app_update(param, param.filename, &log_res);
        }
        // 算法升级
        else if (param.otaType == 3)
        {
            ret = nvr_algorithm_update(param, param.filename, &log_res);
        }
        // 配置升级
        else if (param.otaType == 4)
        {
            ret = nvr_config_update(param, param.filename, &log_res);
        }
        // 鹰眼升级
        else if (param.otaType == 11)
        {
            putJsonToOtaFile(pcJson);
            ret = nvr_EagleEyeSMG_update(param, param.filename, &log_res);
            /*

            if (ret != 200)
            {
                log_res.code = 523;
                log_res.body = "update error";
                StructToJson_LogUploadRes(&psJson, &log_res, true);
                IOTA_SendMqtt("/v1/devices/ota/response", psJson, strlen(psJson));
            }*/
        }
        // 整包升级
        else if (param.otaType == 12 || param.otaType == 20)
        {

            putJsonTonvr_firmwareFile(pcJson);
            putJsonTonvr_algorithmFile(pcJson);
            //putJsonToOtaFile(pcJson);
            ret = nvr_package_update(param, param.filename, &log_res);
            if(ret == 109109)
            {
            	putJsonToOtaFile(pcJson);
            	ret = nvr_EagleEyeSMG_update(param, param.filename, &log_res);
            	param.otaType = 11;
            }
            
        }
        else
        {
            isError = true;
            log_res.code = 404;
            dzlog_error("code error :%d not support", param.otaType);
	    //pthread_mutex_unlock(&g_mutex);
            goto Uerror;
        }
    }
    // 子设备升级
    else if (param.deviceType == 1)
    {
    	// child devices升级
        if (param.otaType == 13)
        {
            
            ret = nvr_childDevice_update(param, param.filename, &log_res);
        }
        else
        ret = sub_update(param, &log_res);
    }

    ///////////////////////appm single way end
    //pthread_mutex_unlock(&g_mutex);

    GF_GetGUID(uid);
    log_res.code = ret;
    if (ret == 0)
    {
        log_res.code = 200;
    }
    // if (log_res.code == 200)

    if ((param.otaType != 1 && param.otaType != 11) || log_res.code >= 300/*log_res.code > 200*/)
    {
        char cmd[4096] = {0};

        //sprintf(cmd, "rm -rf %s/%s", APP_FILE_PATH, param.fileId);
        sprintf(cmd, "rm -rf %s", APP_FILE_PATH);
        system(cmd);
        sprintf(cmd, "rm -rf /userdata/tmp/package/%s", param.filename);
        system(cmd);
    }
    StructToJson_LogUploadRes(&psJson, &log_res, true);
    IOTA_SendMqtt("/v1/devices/ota/response", psJson, strlen(psJson));

    if (g_st_model_ctl.appModules == 1)
    {
        if (param.otaType == 2)
        {
            pthread_t thread;
            pthread_attr_t attr;
            // 初始化线程属性
            pthread_attr_init(&attr);
            // 将线程设置为分离状态
            pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

            // 创建线程
            pthread_create(&thread, &attr, update_app_status_pthread, NULL);
            // 销毁线程属性对象
            pthread_attr_destroy(&attr);
        }
    }
Uerror:
    if (isError)
    {
        GF_GetGUID(uid);
        log_res.body = "update error";
        StructToJson_LogUploadRes(&psJson, &log_res, true);
        IOTA_SendMqtt("/v1/devices/ota/response", psJson, strlen(psJson));
    }
    
    if(log_res.code >= 200)
    {
    		g_process_flag = 0;
    }
    
Ufree:
    free_s(log.iMid);
    free_s(log.deviceSn);
    free_s(log.deviceID);
    free_s(log.msgTime);
    free_s(log.node);
    free_s(log.requestID);
    free_s(log.Servicename);
    free_s(log.zone);
    free_s(param.fileId);
    free_s(param.patchId);
    free_s(param.patchName);
    free_s(param.patchVersion);
    free_s(param.filename);
    free_s(param.subDeviceid);
    
    free_s(psJson);
    free_s(pcJson);
    return 0;
}

int ota_install(char *pcJson)
{ // 分线程
    pthread_t thread;
    pthread_attr_t attr;
    char *psJson = strdup(pcJson);
    // 初始化线程属性
    pthread_attr_init(&attr);

    // 将线程设置为分离状态
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

    // 创建线程
    pthread_create(&thread, &attr, ota_install_pthread, psJson);
    // 销毁线程属性对象
    pthread_attr_destroy(&attr);
    return 0;
}

int reCmd(char *mid)
{
    // int flag = 0;
    //pthread_mutex_lock(&g_mutex);
    int i = 0;
    for (; i < 50; ++i)
    {
        if (strcmp(recmdArray[i], mid) == 0)
        {
            //pthread_mutex_unlock(&g_mutex);
            return 1;
        }
    }
    if (recmdCount == 50)
    {
        recmdCount = 0;
    }
    strcpy(recmdArray[recmdCount++], mid);
    //pthread_mutex_unlock(&g_mutex);
    return 0;
}

int ota_commond(char *pcJson)
{
    g_restart_flag = 1;
    cJSON *json = NULL;
    char cmd[32] = {0};
    char mid[64] = {0};
    json = cJSON_Parse(pcJson);
    if (json)
    {
        strncpy(cmd, cJSON_GetObjectItem(json, "cmd")->valuestring, sizeof(cmd));
        strcpy(mid, cJSON_GetObjectItem(json, "mid")->valuestring);
        //if (reCmd(mid))
        //{
        //    dzlog_error("ota_commond re cmd[%s] exit!!!!!!!!!!!!!!", cmd);
        //    return 0;
        //}
        dzlog_info("ota_commond cmd[%s] ", cmd);

        if (strstr(cmd, "otaPatchDownload"))
        {
            ota_download(pcJson);
        }
        if (strstr(cmd, "otaPatchInstall"))
        {
            ota_install(pcJson);
        }

        cJSON_Delete(json);
    }
    return 0;
}
/// @brief 升级后执行
void nvr_firmware_updated_check()
{
    dzlog_info("updated_check start");
    FILE *fp = fopen("./nvr_firmware.ini", "r");

    char line[100];
    char *last_line = NULL;
    if (fp == NULL)
    {
        // dzlog_error("can not open file upgradeStatus.ini\n");
        return;
    }
    FILE *json = fopen("./nvr_firmware.json", "r");
    if (json == NULL)
    {
        // dzlog_error("can not open file ota.json\n");
        fclose(fp);
        return;
    }
    char json_line[2048] = {0};
    char buffer[2048] = {0};
    while (fgets(json_line, sizeof(json_line), json))
    {
        strcat(buffer, json_line);
    }
    dzlog_debug("buffer = %s", buffer);

    // 还原当时的请求报文
    ST_IOTA_LOG log;
    IOTA_OTA_UPDATE_PARAM param;
    log.param = &param;
    JsonToStruct_DownloadOTAPackUpdate(buffer, &log);
    dzlog_info("updated_check 3");
    char uid[80] = {0};
    GF_GetGUID(uid);
    ST_IOTA_LOG_RES log_res;
    log_res.body = "";
    log_res.deviceID = log.deviceID;
    log_res.deviceSn = log.deviceSn;
    log_res.iMid = uid;
    log_res.node = log.node;
    log_res.replyId = log.iMid;
    log_res.requestID = log.requestID;
    log_res.zone = log.zone;
    char *psJson;
    int time_out = 0;

    dzlog_info("updated_check 4");

    {

        // char c = fgetc(fp);

        // if (c == '0') // callback
        char buf[4096] = {0};
        char buf1[4096] = {0};

        // fread(buf, 1, 1024, fp);
        FILE *fp1 = popen("devinfo -a", "r");

        int n = fread(buf1, 1, 4096, fp1);
        printf("devinfo -a:\n%s\n!!!", buf1);
        pclose(fp1);
        int isAllSuccess = 1;
        char appId[128] = {0};
        char appName[128] = {0};
        char appVersion[128] = {0};
        int isPackageflag = 0;
        while (fgets(buf, 4096, fp) != NULL)
        {
            (buf[strlen(buf) - 1] == '\n') && (buf[strlen(buf) - 1] = '\0');
            char *token = strtok(buf, ",");
            int count = 0;

            while (token != NULL)
            {
                // 查找 RX 数据包数量
                if (count == 0)
                {
                    strcpy(appId, token);
                }
                else if (count == 1)
                {
                    strcpy(appName, token);
                }
                else if (count == 2)
                {
                    strcpy(appVersion, token);
                }
                token = strtok(NULL, ",");
                count++;
                isPackageflag = 1;
            }
            if (!strstr(buf1, appVersion))
            {
                if (isAllSuccess == 1)
                {
                    isAllSuccess = 0;
                }
                send_package_progress(515, -1, appId, appName, appVersion, &log_res);
                dzlog_info("error nvr_firmware_updated_check appVersion = %s", appVersion);
                dzlog_info("error nvr_firmware_updated_check devinfo -a = %s", buf1);
                dzlog_info("error nvr_firmware_updated_check %s not found in %s", appVersion,buf1);
            }
            else
            {
                send_package_progress(200, -1, appId, appName, appVersion, &log_res);
            }
        }

        if (isAllSuccess == 0)
        {
            log_res.code = 515;
        }
        else
        {
            // dzlog_info("updated_check 5");
            log_res.code = 200;
            // dzlog_info("updated_check 6");
        }
        if(0 == isPackageflag)
        {
        	
        	if (!strstr(buf1, buf))
        	{
        		log_res.code = 515;
        	}
        	else
        	{
   			log_res.code = 200;
   		}
        }
        char cmd[4096] = {0};

        sprintf(cmd, "rm -rf %s/%s", APP_FILE_PATH, param.fileId);
        system(cmd);
        memset(uid, 0, 80);
        GF_GetGUID(uid);

        StructToJson_LogUploadRes(&psJson, &log_res, true);
        // dzlog_info("updated_check 8");
        IOTA_SendMqtt("/v1/devices/ota/response", psJson, strlen(psJson));

        // dzlog_info("updated_check 7");
        /*
        char statusPath_cmd[4096] = {0};
    char pathbuf[255] = {0};
    memcpy(pathbuf, param.filename,strstr(param.filename,".tar.gz") - param.filename);
    sprintf(statusPath_cmd, "ls -l %s/%s/%s/*_upgradeStatus.ini", APP_FILE_PATH, param.fileId,pathbuf);


    FILE *fp1 = NULL;
    char buf1[512];
    char buf2[10][512];
    int index = 0;

    if ((fp1 = popen(statusPath_cmd, "r")) == NULL)
    {
        //pclose(fp);
        return -1;
    }
    dzlog_info("statusPath_cmd[%s]",statusPath_cmd);
    while (fgets(buf1, 512, fp1) != NULL)
    {
        (buf1[strlen(buf1) - 1] == '\n') && (buf1[strlen(buf1) - 1] = '\0');
        strcpy(buf2[index++],buf1);
    }
    pclose(fp1);
    //sprintf(statusPath_cmd, "cat %s/%s/%s/%s_upgradeStatus.ini", APP_FILE_PATH, param.fileId,pathbuf,param.fileName);
    int i = 0;
    for(;i < index;++i)
    {
        sprintf(statusPath_cmd, "cat %s", buf2[i]);
        FILE *fp = NULL;
        char buf[256];

        if ((fp = popen(statusPath_cmd, "r")) == NULL)
        {
            continue;
        }
        dzlog_info("statusPath_cmd[%s]",statusPath_cmd);
        while (fgets(buf, 255, fp) != NULL)
        {
            if(strstr(buf,"No such file or directory"))
            {
                continue;
            }

            dzlog_info("buf[%s]",buf);


            char *p = strstr(buf,":");
            if(!p)
            {
                continue;
            }
            (buf[strlen(buf) - 1] == '\n') && (buf[strlen(buf) - 1] = '\0');
            p++;

            if(atoi(buf) >= 200)
            {
                log_res.code = atoi(buf);
                memset(uid, 0, 80);
                    GF_GetGUID(uid);

                    StructToJson_LogUploadRes(&psJson, &log_res, true);
                    // dzlog_info("updated_check 8");
                    IOTA_SendMqtt("/v1/devices/ota/response", psJson, strlen(psJson));
                    // dzlog_info("updated_check 9");
                break;
            }
        }
        pclose(fp);
    }

        char cmd[4096] = {0};
        sprintf(cmd, "rm -rf %s/%s", APP_FILE_PATH, param.fileId);
        system(cmd);*/
    }
    char cmd[4096] = {0};
    sprintf(cmd, "rm -rf %s/*", APP_FILE_PATH);
    system(cmd);
    fclose(fp);
    fclose(json);
    dzlog_info("updated_check 10");
    system("rm -rf ./nvr_firmware.json");
    system("rm -rf ./nvr_firmware.ini");

    free_s(log.iMid);
    free_s(log.deviceSn);
    free_s(log.deviceID);
    free_s(log.msgTime);
    free_s(log.node);
    free_s(log.requestID);
    free_s(log.Servicename);
    free_s(log.zone);
    free_s(param.fileId);
    free_s(param.patchId);
    free_s(param.patchName);
    free_s(param.patchVersion);
    free_s(param.filename);
    free_s(param.subDeviceid);
    free_s(psJson);
}
/// @brief 111升级后执行
void nvr_algorithm_updated_check()
{
    dzlog_info("nvr_algorithm_updated_check start");
    int isPackageflag = 0;
    FILE *fp1 = fopen("./nvr_algorithm.ini", "r");
    if (fp1 != NULL)
    {
        // dzlog_error("can not open file upgradeStatus.ini\n");

        //return;
        isPackageflag = 1;
    }
    FILE* json = fopen("./nvr_algorithm.json", "r");
    if (json == NULL)
    {
        // dzlog_error("can not open file ota.json\n");
        if (fp1)
        {
            fclose(fp1);
        }
        return;
    }
    char json_line[2048] = {0};
    char buffer[2048] = {0};
    while (fgets(json_line, sizeof(json_line), json))
    {
        strcat(buffer, json_line);
    }
    dzlog_debug("buffer = %s", buffer);
    fclose(json);
    // 还原当时的请求报文
    ST_IOTA_LOG log;
    IOTA_OTA_UPDATE_PARAM param;
    log.param = &param;
    JsonToStruct_DownloadOTAPackUpdate(buffer, &log);
    dzlog_info("updated_check 3");
    char uid[80] = {0};
    GF_GetGUID(uid);
    ST_IOTA_LOG_RES log_res;
    log_res.body = "";
    log_res.deviceID = log.deviceID;
    log_res.deviceSn = log.deviceSn;
    log_res.iMid = uid;
    log_res.node = log.node;
    log_res.replyId = log.iMid;
    log_res.requestID = log.requestID;
    log_res.zone = log.zone;
    char *psJson = NULL;
    int time_out = 0;

    dzlog_info("updated_check 5");
    FILE *fp = NULL;
    char buf[255] = {0};
    char statusPath_cmd[4096] = {0};
    char pathbuf[255] = {0};
    memcpy(pathbuf, param.filename, strstr(param.filename, ".tar.gz") - param.filename);
    sprintf(statusPath_cmd, "cat %s/%s/%s/*_upgradeStatus.ini", APP_FILE_PATH, param.fileId, pathbuf);
    //
    int k = 0;
    char *p = NULL;
    while (k++ < 50)
    {
        sleep(2);

        if ((fp = popen(statusPath_cmd, "r")) == NULL)
        {
            system("rm -rf ./nvr_algorithm.json");
            fclose(fp1);
            goto Ufree;
            // return;
        }
        while (fgets(buf, 255, fp) != NULL)
        {
            if (strstr(buf, "No such file or directory"))
            {
                pclose(fp);
                fclose(fp1);
                system("rm -rf ./nvr_algorithm.json");
                goto Ufree;
                // return;
            }
            dzlog_debug("buf = %s", buf);
        }
        pclose(fp);

        p = strstr(buf, ":");
        if (!p)
        {
            system("rm -rf ./nvr_algorithm.json");
            fclose(fp1);
            goto Ufree;
            // return;
        }
        (buf[strlen(buf) - 1] == '\n') && (buf[strlen(buf) - 1] = '\0');
        p++;
        if (atoi(p) >= 200)
        {
            break;
        }
    }

    ///
    char appId[128] = {0};
    char appName[128] = {0};
    char appVersion[128] = {0};
    char buf1[4096] = {0};
    while (fgets(buf1, 4096, fp1) != NULL)
    {
        (buf1[strlen(buf1) - 1] == '\n') && (buf1[strlen(buf1) - 1] = '\0');
        char *token = strtok(buf1, ",");
        int count = 0;

        while (token != NULL)
        {
            // 查找 RX 数据包数量
            if (count == 0)
            {
                strcpy(appId, token);
            }
            else if (count == 1)
            {
                strcpy(appName, token);
            }
            else if (count == 2)
            {
                strcpy(appVersion, token);
            }
            token = strtok(NULL, ",");
            count++;
        }
    }
    fclose(fp1);
    ///
    log_res.code = atoi(p);
    if (log_res.code < 200 || k >= 50)
    {
        log_res.code = 515;
        if(k >= 50)
        {
        	dzlog_info("error nvr_algorithm_updated_check timeout = %d s", k*2);
        }
    }

    if (isPackageflag == 1)
    {
        send_package_progress(log_res.code, -1, appId, appName, appVersion, &log_res);
    }

    char cmd[4096] = {0};

    sprintf(cmd, "rm -rf %s/%s", APP_FILE_PATH, param.fileId);
    system(cmd);
    memset(uid, 0, 80);
    GF_GetGUID(uid);

    StructToJson_LogUploadRes(&psJson, &log_res, true);
    // dzlog_info("updated_check 8");
    IOTA_SendMqtt("/v1/devices/ota/response", psJson, strlen(psJson));

    dzlog_info("updated_check 11");
    system("rm -rf ./nvr_algorithm.json");


Ufree:
    free_s(log.iMid);
    free_s(log.deviceSn);
    free_s(log.deviceID);
    free_s(log.msgTime);
    free_s(log.node);
    free_s(log.requestID);
    free_s(log.Servicename);
    free_s(log.zone);
    free_s(param.fileId);
    free_s(param.patchId);
    free_s(param.patchName);
    free_s(param.patchVersion);
    free_s(param.filename);
    free_s(param.subDeviceid);
    free_s(psJson);
    return;
}
/// @brief 升级后执行
void otaEagleEyeSMG_updated_check2()
{
    nvr_algorithm_updated_check();
    nvr_firmware_updated_check();
    dzlog_info("otaEagleEyeSMG_updated_check start");
    FILE *fp = fopen("./otaEagleEyeSMG.ini", "r");
    FILE *fp3 = fopen("./nvr_EagleEyeSMG.ini", "r");

    char line[100];
    char *last_line = NULL;

    if (fp == NULL)
    {
        dzlog_error("can not open file upgradeStatus.ini\n");
        return;
    }
    FILE *json = fopen("./otaEagleEyeSMG.json", "r");
    if (json == NULL)
    {
        dzlog_error("can not open file ota.json\n");
        fclose(fp);
        return;
    }
    dzlog_info("updated_check 2");
    char json_line[2048] = {0};
    char buffer[2048] = {0};
    while (fgets(json_line, sizeof(json_line), json))
    {
        strcat(buffer, json_line);
    }
    dzlog_debug("buffer = %s", buffer);

    // 还原当时的请求报文
    ST_IOTA_LOG log;
    IOTA_OTA_UPDATE_PARAM param;
    log.param = &param;
    JsonToStruct_DownloadOTAPackUpdate(buffer, &log);
    dzlog_info("updated_check 3");
    char uid[80] = {0};
    GF_GetGUID(uid);
    ST_IOTA_LOG_RES log_res;
    log_res.body = "";
    log_res.deviceID = log.deviceID;
    log_res.deviceSn = log.deviceSn;
    log_res.iMid = uid;
    log_res.node = log.node;
    log_res.replyId = log.iMid;
    log_res.requestID = log.requestID;
    log_res.zone = log.zone;
    char *psJson;
    int time_out = 0;

    dzlog_info("updated_check 4");

    {

        char c = fgetc(fp);

        if (c == '0') // callback
        {
            log_res.code = 523;
        }
        else
        {
            // dzlog_info("updated_check 5");
            log_res.code = 200;
            nvr_EagleEyeSMG_update_107(param, param.filename, &log_res);
            // dzlog_info("updated_check 6");
        }
        // dzlog_info("updated_check 7");
        memset(uid, 0, 80);
        GF_GetGUID(uid);

        StructToJson_LogUploadRes(&psJson, &log_res, true);
        
        ///
        if(fp3)
        {
    		char appId[128] = {0};
    		char appName[128] = {0};
    		char appVersion[128] = {0};
    		char buf1[4096] = {0};
    		while (fgets(buf1, 4096, fp3) != NULL)
    		{
        		(buf1[strlen(buf1) - 1] == '\n') && (buf1[strlen(buf1) - 1] = '\0');
        		char *token = strtok(buf1, ",");
        		int count = 0;

        		while (token != NULL)
        		{
            		// 查找 RX 数据包数量
            		if (count == 0)
            		{
                		strcpy(appId, token);
            		}
            		else if (count == 1)
            		{
                		strcpy(appName, token);
            		}
            		else if (count == 2)
            		{
                		strcpy(appVersion, token);
            		}
            		token = strtok(NULL, ",");
            		count++;
        		}
    		}
    		fclose(fp3);
    		send_package_progress(log_res.code, -1, appId, appName, appVersion, &log_res);
    	}
        while (1)
        {
            int ret2 = IOTA_SendMqtt("/v1/devices/ota/response", psJson, strlen(psJson));
            if (ret2 == 0)
            {
                break;
            }
            else
            {
                sleep(5);
            }
        }
    }
    fclose(fp);
    fclose(json);
    dzlog_info("updated_check 10");
    system("rm -rf ./otaEagleEyeSMG.json");
    system("rm -rf ./otaEagleEyeSMG.ini");
    system("rm -rf ./nvr_EagleEyeSMG.ini");
    system("rm -rf ../EagleEyeSMGbak");
    char cmd[4096] = {0};
    sprintf(cmd, "rm -rf %s/*", APP_FILE_PATH);
    system(cmd);

    free_s(log.iMid);
    free_s(log.deviceSn);
    free_s(log.deviceID);
    free_s(log.msgTime);
    free_s(log.node);
    free_s(log.requestID);
    free_s(log.Servicename);
    free_s(log.zone);
    free_s(param.fileId);
    free_s(param.patchId);
    free_s(param.patchName);
    free_s(param.patchVersion);
    free_s(param.filename);
    free_s(param.subDeviceid);
    free_s(psJson);
}
/// @brief 升级后执行
void otaEagleEyeSMG_updated_check()
{
    if(g_restart_flag)
    {
    	return;
    }
    FILE *fp1 = fopen("./secEagleEyeSMG.ini", "r");
    if(fp1)
    {
    	fclose(fp1);
    	system("rm -rf ./*.json");
    	system("rm -rf ./*.ini");
    	return;
    }
    system("touch ./secEagleEyeSMG.ini");
    
	otaEagleEyeSMG_updated_check2();
	char cmd[4096] = {0};
    sprintf(cmd, "rm -rf %s/*", APP_FILE_PATH);
    system(cmd);
    system("rm -rf ./secEagleEyeSMG.ini");
}
